package com.fast.alden.admin;

import com.fast.alden.admin.util.Constants;
import com.fast.alden.data.model.SysApiResource;
import com.fast.alden.data.repo.SysApiResourceRepository;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.Resource;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Component
public class InitializeSysTestData implements CommandLineRunner {
    @Resource
    private RequestMappingHandlerMapping handlerMapping;
    @Resource
    private EntityManager entityManager;
    @Resource
    private SysApiResourceRepository apiResourceRepository;

    @Override
    @Transactional
    public void run(String... args) throws Exception {
        scanUrls();

    }

    private void scanUrls() {
        List<SysApiResource> resourcesInDb = apiResourceRepository.findAll();

        Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();

        Set<SysApiResource> resources = new HashSet<>();

        handlerMethods.keySet().forEach(
                requestMappingInfo -> {
                    HandlerMethod handlerMethod = handlerMethods.get(requestMappingInfo);
                    // 只收录com.fast.alden.admin.web.controller包下的api资源
                    if (!handlerMethod.getMethod().getDeclaringClass().getPackageName().startsWith(Constants.CONTROLLER_PACKAGE_NAME_PREFIX)) {
                        return;
                    }
                    // todo： warning: 此处要求controller层每个方法只能有一个RequestMapping，且只能接受一个HttpMethod
                    String pattern = requestMappingInfo.getPatternValues().stream().findFirst().orElse(null);
                    RequestMethod method = requestMappingInfo.getMethodsCondition().getMethods().stream().findFirst().orElse(null);
                    if (pattern != null) {
                        SysApiResource resource = new SysApiResource();
                        resource.setName(requestMappingInfo.getName());
                        resource.setUrl(pattern);
                        resource.setMethod(method != null ? method.name() : null);
                        resource.setHandler(handlerMethod.toString());
                        if (handlerMethod.getMethod().getDeclaredAnnotation(Operation.class) != null) {
                            resource.setName(handlerMethod.getMethod().getDeclaredAnnotation(Operation.class).summary());
                        }

                        // 默认需要指定角色
                        resource.setRequireLogin(true);
                        resource.setRequirePermissions(true);
                        if (pattern.matches("^.*/auth/login$") || pattern.matches("^.*/auth/verify-code$")) {
                            // 验证码、登录无需授权
                            resource.setRequireLogin(false);
                            resource.setRequirePermissions(false);
                        } else if (pattern.matches("^.*/auth/logout$") || pattern.matches("^.*/profile/.*$") || pattern.matches("^.*/message-center/.*$")) {
                            // 注销、个人中心只需要登录
                            resource.setRequireLogin(true);
                            resource.setRequirePermissions(false);
                        }

                        // 如果数据库中已存在相同的api资源则忽略
                        if (resourcesInDb.stream().noneMatch(res -> res.getUrl().equals(resource.getUrl()) && res.getMethod().equals(resource.getMethod()) && res.getHandler().equals(resource.getHandler()))) {
                            resources.add(resource);
                        }

                    }
                }
        );

        apiResourceRepository.saveAll(resources);
    }
}
